package com.ftg.learn.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

/**
 * JWT工具类
 *
 * @author 布衣
 */
@Slf4j
public class JwtUtils {
    
    /**
     * 默认过期时间 24小时（毫秒）
     */
    private static final long DEFAULT_EXPIRATION = 24 * 60 * 60 * 1000L;
    
    /**
     * JWT签名密钥 - 使用包含指定字符串且长度足够的安全密钥
     */
    private static final SecretKey SECRET_KEY = generateSecureKey("www.ftgyun.top");
    
    /**
     * 生成包含指定字符串且满足HS512算法安全要求的密钥
     * HS512要求密钥至少512位(64字节)
     *
     * @param baseString 基础字符串
     * @return 符合安全要求的SecretKey
     */
    public static SecretKey generateSecureKey(String baseString) {
        if (baseString == null || baseString.isEmpty()) {
            throw new IllegalArgumentException("基础字符串不能为空");
        }
        
        // 构建满足长度要求的密钥字符串
        StringBuilder keyBuilder = new StringBuilder();
        while (keyBuilder.length() < 64) {
            keyBuilder.append(baseString);
        }
        
        // 截取正好64字节的字符串
        String keyString = keyBuilder.substring(0, 64);
        
        // 转换为SecretKey
        return Keys.hmacShaKeyFor(keyString.getBytes());
    }
    
    /**
     * 生成Base64编码的密钥字符串，可用于配置文件存储
     *
     * @param baseString 基础字符串
     * @return Base64编码的密钥字符串
     */
    public static String generateBase64KeyString(String baseString) {
        if (baseString == null || baseString.isEmpty()) {
            throw new IllegalArgumentException("基础字符串不能为空");
        }
        
        // 构建满足长度要求的密钥字符串
        StringBuilder keyBuilder = new StringBuilder();
        while (keyBuilder.length() < 64) {
            keyBuilder.append(baseString);
        }
        
        // 截取正好64字节的字符串
        String keyString = keyBuilder.substring(0, 64);
        
        // 返回Base64编码的字符串
        return Base64.getEncoder().encodeToString(keyString.getBytes());
    }
    
    /**
     * 从Base64编码的字符串生成SecretKey
     *
     * @param base64Key Base64编码的密钥字符串
     * @return SecretKey对象
     */
    public static SecretKey generateKeyFromBase64String(String base64Key) {
        if (base64Key == null || base64Key.isEmpty()) {
            throw new IllegalArgumentException("Base64密钥字符串不能为空");
        }
        
        byte[] keyBytes = Base64.getDecoder().decode(base64Key);
        return Keys.hmacShaKeyFor(keyBytes);
    }
    
    /**
     * 生成JWT Token
     *
     * @param subject   主题
     * @param claims    自定义声明
     * @return 生成的JWT Token字符串
     */
    public static String generateToken(String subject, Map<String, Object> claims) {
        return generateToken(subject, claims, DEFAULT_EXPIRATION);
    }
    
    /**
     * 生成JWT Token
     *
     * @param subject    主题
     * @param claims     自定义声明
     * @param expiration 过期时间（毫秒）
     * @return 生成的JWT Token字符串
     */
    public static String generateToken(String subject, Map<String, Object> claims, long expiration) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expiration);
        
        JwtBuilder builder = Jwts.builder()
                .setSubject(subject)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SECRET_KEY, SignatureAlgorithm.HS512);
        
        // 添加自定义声明
        if (claims != null && !claims.isEmpty()) {
            builder.addClaims(claims);
        }
        
        return builder.compact();
    }
    
    /**
     * 解析JWT Token
     *
     * @param token JWT Token字符串
     * @return Claims对象
     * @throws JwtException 当Token无效时抛出
     */
    public static Claims parseToken(String token) throws JwtException {
        return Jwts.parser()
                .verifyWith(SECRET_KEY)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }
    
    /**
     * 验证JWT Token是否有效
     *
     * @param token JWT Token字符串
     * @return true表示有效，false表示无效
     */
    public static boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (SignatureException e) {
            log.error("Invalid JWT signature: {}", e.getMessage());
        } catch (MalformedJwtException e) {
            log.error("Invalid JWT token: {}", e.getMessage());
        } catch (ExpiredJwtException e) {
            log.error("Expired JWT token: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            log.error("Unsupported JWT token: {}", e.getMessage());
        } catch (IllegalArgumentException e) {
            log.error("JWT claims string is empty: {}", e.getMessage());
        }
        return false;
    }
    
    /**
     * 从JWT Token中获取主题(subject)
     *
     * @param token JWT Token字符串
     * @return 主题(subject)
     */
    public static String getSubjectFromToken(String token) {
        try {
            Claims claims = parseToken(token);
            return claims.getSubject();
        } catch (JwtException e) {
            log.error("Failed to get subject from token: {}", e.getMessage());
            return null;
        }
    }
}
